package net.cloudcodex.server.rpc;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import net.cloudcodex.server.Context;
import net.cloudcodex.server.DTOUtil;
import net.cloudcodex.server.data.Data;
import net.cloudcodex.server.data.campaign.character.CharacterDescriptionSDO;
import net.cloudcodex.server.data.campaign.character.CharacterSDO;
import net.cloudcodex.server.data.campaign.msg.SceneSDO;
import net.cloudcodex.server.data.campaign.scene.SceneToCreateSDO;
import net.cloudcodex.server.data.home.CampaignSummary;
import net.cloudcodex.shared.MessageAction;
import net.cloudcodex.shared.dto.Result;
import net.cloudcodex.shared.dto.campaign.character.CharacterDescriptionDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterHeaderDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterNoteDTO;
import net.cloudcodex.shared.dto.campaign.character.CompleteCharacterDescriptionDTO;
import net.cloudcodex.shared.dto.home.CampaignSummaryDTO;
import net.cloudcodex.shared.dto.msg.SceneDTO;
import net.cloudcodex.shared.dto.msg.SceneToCreateDTO;
import net.cloudcodex.shared.rpc.CampaignRPC;

/**
 * RPC for Campaign, Scene and Message.
 * @author Thomas
 */
@SuppressWarnings("serial")
public class CampaignRPCImpl extends AbstractRPC implements CampaignRPC {

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<CampaignSummaryDTO> createCampaign(String name, String game, 
			String description, String icon) {

		final Context context = createContext();
		
		final Data.Campaign campaign =
			campaignService.createCampaign(context, name, game, 
					description, icon, context.getUser());

		final CampaignSummary summary = new CampaignSummary();
		summary.setCampaign(campaign);
		summary.setMaster(context.getUser());
		summary.setNotifications(null);
		summary.setCharacters(null);
		
		return createResult(context, DTOUtil.mapCampaignSummary(summary));
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<CampaignSummaryDTO> updateCampaign(long campaignId, 
			String name, String game, 
			String description, String icon) {

		final Context context = createContext();
		
		final Data.Campaign campaign =
			campaignService.updateCampaign(context, campaignId, name, game, 
					description, icon, context.getUser());

		final CampaignSummary summary = new CampaignSummary();
		summary.setCampaign(campaign);
		summary.setMaster(context.getUser());
		summary.setNotifications(null);
		summary.setCharacters(null);
		
		return createResult(context, DTOUtil.mapCampaignSummary(summary));
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<CharacterHeaderDTO> inviteToCampaign(long campaignId, String email, String name) {

		final Context context = createContext();
		
		final CharacterSDO character =
			campaignService.inviteToCampaign(context, campaignId, email, name);

		return createResult(context, DTOUtil.mapCharacterSDOToHeader(character, null));
	}
	
	/**
	 * Creates a NPC.
	 */
	@Override
	public Result<CharacterHeaderDTO> addNPC(long campaignId, String name, 
			String description, String icon, boolean profile) {
		
		final Context context = createContext();
		
		final CharacterSDO character = campaignService.createNPC(
				context, campaignId, name, icon, description, profile);

		return createResult(context, DTOUtil.mapCharacterSDOToHeader(character, null));
	}
	
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<List<CharacterHeaderDTO>> getCampaignCharacters(long campaignId) {
		final Context context = createContext();
		
		final List<CharacterSDO> characters = 
			campaignService.getCampaignCharacters(context, campaignId);
		
		if(characters == null) {
			return new Result<List<CharacterHeaderDTO>>(true, null, null);
		}
		
		// Map SDOs to DTOs
		final List<CharacterHeaderDTO> dtos = DTOUtil.mapCharacterSDOToHeader(characters, null);

		// Return OK result with DTOs.
		return createResult(context, dtos);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<CharacterDescriptionDTO> getCharacterDescription(
			long campaignId, long characterId, 
			Long byCharacterId, Date timestamp) {
		
		final Context context = createContext();

		final CharacterDescriptionSDO sdo = campaignService.getCharacterDescription(
				context, campaignId, characterId, byCharacterId, timestamp);
		
		final CharacterDescriptionDTO dto = DTOUtil.mapCharacterDescription(sdo);
		
		return createResult(context, dto);
	}
	

	@Override
	public Result<CompleteCharacterDescriptionDTO> getCharacterCompleteDescription(
			long campaignId, long characterId) {

		final Context context = createContext();
		
		final CompleteCharacterDescriptionDTO dto = new CompleteCharacterDescriptionDTO();

		// Get the header.
		final CharacterSDO character = campaignService.getCharacter(context, campaignId, characterId);
		dto.setHeader(DTOUtil.mapCharacterSDOToHeader(character, characterId));

		// Get the description.
		final CharacterDescriptionSDO sdo = campaignService.getCharacterDescription(
				context, campaignId, characterId, characterId, null);
		
		dto.setDescription(DTOUtil.mapCharacterDescription(sdo));

		return createResult(context, dto);
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<CharacterDescriptionDTO> updateCharacterDescription(
			long campaignId, long characterId, Long byCharacterId,
			String description, String sheet, Boolean dead, Boolean locked,
			List<CharacterNoteDTO> notes, Map<Long, String> aliases) {
		
		final Context context = createContext();
		
		final Map<Long, String> map = new HashMap<Long, String>();
		for(CharacterNoteDTO note : notes) {
			if(note != null) {
				map.put(note.getAuthor(), note.getContent());
			}
		}

		final CharacterDescriptionSDO sdo = 
			campaignService.updateCharacterDescription(
				context, campaignId, characterId, byCharacterId, 
				description, sheet, dead, locked,
				map, aliases);

		if(sdo == null) {
			return new Result<CharacterDescriptionDTO>(false, null, null);
		}

		return createResult(context, DTOUtil.mapCharacterDescription(sdo));
	}
	
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<List<SceneDTO>> getMessages(long campaignId, long characterId,
			Long lastSceneId, Date timestamp) {
		
		final Context context = createContext();
		
		final List<SceneSDO> scenes = messageService.getMessages(
				context, campaignId, characterId, lastSceneId, timestamp);

		if(scenes == null) {
			return new Result<List<SceneDTO>>(false, null, null);
		}
		
		final List<SceneDTO> dtos = DTOUtil.mapScene(scenes, characterId);
		
		return createResult(context, dtos);
	}
	

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<Boolean> justForTestsDoSomethingRandomly(long campaignId, long characterId, int action) {
		
		final Context context = createContext();
		final boolean result;
		if(action == 0) {
			return justForTestsDoSomethingRandomly(campaignId, characterId, new Random().nextInt(6) + 1);
		} else if(action == 1) {
			result = messageService.justForTestsCreateSequenceRandomly(context, campaignId, characterId);
		} else if(action == 2) {
			result = messageService.justForTestsMakeThemTalkRandomly(context, campaignId, characterId);
		} else if(action == 3) {
			result = messageService.justForTestsInsertOFFRandomly(context, campaignId, characterId);
		} else if(action == 4) {
			result = messageService.justForTestsDeleteMessageRandomly(context, campaignId, characterId);
		} else if(action == 5) {
			result = messageService.justForTestsMakeThemRollDicesRandomly(context, campaignId, characterId);
		} else if(action == 6) {
			result = messageService.justForTestsReindexRandomly(context, campaignId, characterId);
		} else {
			result = false;
		}
		
		return createResult(context, result);
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<Boolean> playerPostAction(
			long campaignId, long characterId, 
			long clientSceneId, Date clientSceneTimestamp,
			MessageAction action, String content) {
		
		final Context context = createContext();
		
		final boolean result = messageService.playerPostAction(
				context, campaignId, characterId, 
				clientSceneId, clientSceneTimestamp, action, content);

		return createResult(context, result);
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<Boolean> playerPostOFF(
			long campaignId, long characterId, 
			long clientSceneId, Date clientSceneTimestamp,
			String content) {
		
		final Context context = createContext();
		
		final boolean result = messageService.playerPostOFF(
				context, campaignId, characterId, 
				clientSceneId, clientSceneTimestamp, content);

		return createResult(context, result);
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Result<Boolean> playerRollDices(
			long campaignId, long characterId, 
			long clientSceneId, Date clientSceneTimestamp,
			Map<Integer, Integer> dices, String content) {
		
		final Context context = createContext();
		
		final boolean result = messageService.playerRollDices(
				context, campaignId, characterId, 
				clientSceneId, clientSceneTimestamp, 
				dices, content);

		return createResult(context, result);
	}
	
	
	@Override
	public Result<Boolean> startScenes(long campaignId,
			SceneToCreateDTO[] scenesDTO) {
		
		
		final Context context = createContext();
	
		final SceneToCreateSDO[] scenes;
		if(scenesDTO == null) {
			scenes = null;
		} else {
			scenes = new SceneToCreateSDO[scenesDTO.length];
			for(int n = 0; n < scenesDTO.length; n++) {
				scenes[n] = DTOUtil.mapSceneToCreate(scenesDTO[n]);
			}
		}
		
		final boolean result = messageService.startScenes(context, campaignId, scenes);

		return createResult(context, result);
	}

}
